#include <boost/algorithm/string.hpp>
#include <fstream>
#include "algo.h"
#include "stl-helper.h"

MatrixData::MatrixData(int labelCol) 
    : labelCol_(labelCol)
{
}

void MatrixData::setSource(std::istream& istream)
{
    int count = 0;
    int n_col = 0;
    while (!istream.eof()) {
        std::string line;
        std::vector<std::string> tokens;
        std::getline(istream, line);
        boost::split(tokens, line, boost::is_any_of("\t ,"));

        if (sz(tokens) == 0) continue;

        //DEBUG_MSG(line << " : " << tokens[0]);

        if (count == 0) 
            n_col = sz(tokens);
        else if (n_col != sz(tokens))
            break; //FATAL_ERROR("Number of columns not equal n_col=" << n_col << " != " << sz(tokens));

        if (labelCol_ >= n_col)
            FATAL_ERROR("Label column index " << labelCol_ << " should be less than number of columns " << n_col);

        datum_type row(n_col);
        for (int i = 0; i < n_col; i++)
            row(i) = RAND::s2type<double>(tokens.at(i));

        if (labelCol_ < 0) 
            x_.pb(row);
        else {
            y_.pb(row(labelCol_));
            datum_type tmp(n_col-1);
            for (int i = 0; i < n_col; i++)
                if (i != labelCol_)
                    tmp(i<labelCol_ ? i : i-1) = row(i);
            x_.pb(tmp);
        }
        count++;
    }
    dim_ = (labelCol_ < 0 ? n_col : n_col-1);
}

void MatrixData::setSource(const std::string& fname)
{
    std::ifstream istream(fname.c_str());
    setSource(istream);
    istream.close();
}

void MatrixData::printTo(std::ostream& ostream)
{
    for (int i = 0; i < sz(x_); i++) {
        if (labelCol_ >= 0) ostream << y_.at(i);
        for (int j = 0; j < nele(x_.at(i)); j++)
            ostream << "\t " << x_.at(i)(j);
        ostream << ENDL;
    }
    //DEBUG_MSG("size = " << sz(x_) << " dim = " << dim());
}

void MatrixData::printTo(const std::string& fname)
{
    std::ofstream ostream(fname.c_str());
    printTo(ostream);
    ostream.close();
}

int MatrixData::dim() const
{
    return dim_;
}

int MatrixData::size() const
{
    return sz(x_);
}

const MatrixData::datum_type& MatrixData::getX(int rowIndex) const
{
    return x_.at(rowIndex);
}

double MatrixData::getY(int rowIndex) const
{
    return y_.at(rowIndex);
}

